#include "mytp.h"
#include <stdlib.h>

int init_task_q(task_q* tq, size_t sz) {
	tq->sz = sz;
	tq->head = 0;
	tq->tail = 0;
	tq->task_queqe = (task_t**) malloc (sz*(sizeof task_t*));
	pthread_mutex_init(tq->mtx);
	pthread_cond_init(tq->empty_cond);
	pthread_cond_init(tq->full_cond);
}

int free_task_q(task_q* tq) {
	free(tq->task_queqe);
	pthread_mutex_destroy(tq->mtx);
	pthread_cond_destroy(tq->empty_cond);
	pthread_cond_destroy(tq->full_cond);
}


int isempty_task_q(task_q* tq_ptr) {
	if (tq_ptr->head == tq_ptr->tail)
			return 0; // empty
	else
			return 1; // not empty
}

int isfull_task_q(task_q* tq_ptr) {
	if ((-tq_ptr->head + tq_ptr->tail + 1) % tq_ptr->sz == 0)
			return 0; // full
	else
			return 1; // not full

}

task_t* de_task_q(task_q* tq_ptr) { // block caller when task_q is empty 
		task_t* res=NULL;
		pthread_mutex_lock(tq_ptr->mtx);
		while (isempty_task_q(tq_ptr)){
			pthread_cond_wait(tq_ptr->empty_cond, tq_ptr->mtx);// use timed wait to prevent deadloop, i.e. no more producer
		}
		res = tq_ptr->task_queqe[tq_ptr->tail];
		tq_ptr->tail = (tq_ptr->tail-1) % tq_ptr->sz;
		pthread_cond_signal(tq_ptr->full_cond); // not full now
		pthread_mutex_unlock(tq_ptr->mtx);
		return res;
}

int en_task_q(task_q* tq_ptr, task_t* t){ // block caller when task_q is full
		pthread_mutex_lock(tq_ptr->mtx);
		while (isfull_task_q(tq_ptr)) {
			pthread_cond_wait(tq_ptr->full_cond, tq_ptr->mtx); // use timed wait to prevent deadloop, i.e. no more consumer
		}
		tq_ptr->task_queqe[tq_ptr->head] = t;
		tq_ptr->head = (tq_ptr->head-1) % tq_ptr->sz;
		pthread_cond_signal(tq_ptr->empty_cond); // not empty now
		pthread_mutex_unlock(tq_ptr->mtx);
		return 0;
}
